home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pine / imap-3.0 / non-ANSI / c-client / smtp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-18  |  8.5 KB  |  288 lines

  1. /*
  2.  * Program:    Simple Mail Transfer Protocol (SMTP) routines
  3.  *
  4.  * Author:    Mark Crispin
  5.  *        Networks and Distributed Computing
  6.  *        Computing & Communications
  7.  *        University of Washington
  8.  *        Administration Building, AG-44
  9.  *        Seattle, WA  98195
  10.  *        Internet: MRC@CAC.Washington.EDU
  11.  *
  12.  * Date:    27 July 1988
  13.  * Last Edited:    18 March 1993
  14.  *
  15.  * Sponsorship:    The original version of this work was developed in the
  16.  *        Symbolic Systems Resources Group of the Knowledge Systems
  17.  *        Laboratory at Stanford University in 1987-88, and was funded
  18.  *        by the Biomedical Research Technology Program of the National
  19.  *        Institutes of Health under grant number RR-00785.
  20.  *
  21.  * Original version Copyright 1988 by The Leland Stanford Junior University.
  22.  * Copyright 1993 by the University of Washington.
  23.  *
  24.  *  Permission to use, copy, modify, and distribute this software and its
  25.  * documentation for any purpose and without fee is hereby granted, provided
  26.  * that the above copyright notices appear in all copies and that both the
  27.  * above copyright notices and this permission notice appear in supporting
  28.  * documentation, and that the name of the University of Washington or The
  29.  * Leland Stanford Junior University not be used in advertising or publicity
  30.  * pertaining to distribution of the software without specific, written prior
  31.  * permission.  This software is made available "as is", and
  32.  * THE UNIVERSITY OF WASHINGTON AND THE LELAND STANFORD JUNIOR UNIVERSITY
  33.  * DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO THIS SOFTWARE,
  34.  * INCLUDING WITHOUT LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  35.  * FITNESS FOR A PARTICULAR PURPOSE, AND IN NO EVENT SHALL THE UNIVERSITY OF
  36.  * WASHINGTON OR THE LELAND STANFORD JUNIOR UNIVERSITY BE LIABLE FOR ANY
  37.  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
  38.  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
  39.  * CONTRACT, TORT (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF
  40.  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  41.  *
  42.  */
  43.  
  44. #include <ctype.h>
  45. #include <stdio.h>
  46. #include "mail.h"
  47. #include "osdep.h"
  48. #include "smtp.h"
  49. #include "rfc822.h"
  50. #include "misc.h"
  51.  
  52. /* Mail Transfer Protocol open connection
  53.  * Accepts: service host list
  54.  *        initial debugging flag
  55.  * Returns: T on success, NIL on failure
  56.  */
  57.  
  58. SMTPSTREAM *smtp_open (hostlist,debug)
  59.     char **hostlist;
  60.     long debug;
  61. {
  62.   SMTPSTREAM *stream = NIL;
  63.   void *tcpstream;
  64.   char tmp[MAILTMPLEN];
  65.   if (!(hostlist && *hostlist)) mm_log ("Missing MTP service host",ERROR);
  66.   else do {            /* try to open connection */
  67.     if (tcpstream = tcp_open (*hostlist,SMTPTCPPORT)) {
  68.                 /* default local host */
  69.       if (!lhostn) lhostn = cpystr (tcp_localhost (tcpstream));
  70.       stream = (SMTPSTREAM *) fs_get (sizeof (SMTPSTREAM));
  71.       stream->tcpstream = tcpstream;
  72.       stream->debug = debug;
  73.       stream->reply = NIL;
  74.                 /* get SMTP greeting */
  75.       if (smtp_reply (stream) == SMTPGREET &&
  76.       ((smtp_send (stream,"HELO",tcp_localhost (tcpstream)) == SMTPOK) ||
  77.        ((!strcmp ("localhost",lcase (strcpy (tmp,*hostlist)))) &&
  78.         (smtp_send (stream,"HELO","localhost") == SMTPOK))))
  79.     return stream;        /* success return */
  80.       smtp_close (stream);    /* otherwise punt stream */
  81.     }
  82.   } while (*++hostlist);    /* try next server */
  83.   return NIL;
  84. }
  85.  
  86.  
  87. /* Mail Transfer Protocol close connection
  88.  * Accepts: stream
  89.  */
  90.  
  91. void smtp_close (stream)
  92.     SMTPSTREAM *stream;
  93. {
  94.   if (stream) {            /* send "QUIT" */
  95.     smtp_send (stream,"QUIT",NIL);
  96.                 /* close TCP connection */
  97.     tcp_close (stream->tcpstream);
  98.     if (stream->reply) fs_give ((void **) &stream->reply);
  99.     fs_give ((void **) &stream);/* flush the stream */
  100.   }
  101. }
  102.  
  103. /* Mail Transfer Protocol deliver mail
  104.  * Accepts: stream
  105.  *        delivery option (MAIL, SEND, SAML, SOML)
  106.  *        message envelope
  107.  *        message body
  108.  * Returns: T on success, NIL on failure
  109.  */
  110.  
  111. long smtp_mail (stream,type,env,body)
  112.     SMTPSTREAM *stream;
  113.     char *type;
  114.     ENVELOPE *env;
  115.     BODY *body;
  116. {
  117.   char tmp[8*MAILTMPLEN];
  118.   long error = NIL;
  119.   if (!(env->to || env->cc || env->bcc)) {
  120.                   /* no recipients in request */
  121.     smtp_fake (stream,SMTPHARDERROR,"No recipients specified");
  122.     return NIL;
  123.   }
  124.                   /* make sure stream is in good shape */
  125.   smtp_send (stream,"RSET",NIL);
  126.   strcpy (tmp,"FROM:<");    /* compose "MAIL FROM:<return-path>" */
  127.   rfc822_address (tmp,env->return_path);
  128.   strcat (tmp,">");
  129.                 /* send "MAIL FROM" command */
  130.   if (!(smtp_send (stream,type,tmp) == SMTPOK)) return NIL;
  131.                 /* negotiate the recipients */
  132.   if (env->to) smtp_rcpt (stream,env->to,&error);
  133.   if (env->cc) smtp_rcpt (stream,env->cc,&error);
  134.   if (env->bcc) smtp_rcpt (stream,env->bcc,&error);
  135.   if (error) {            /* any recipients failed? */
  136.                       /* reset the stream */
  137.     smtp_send (stream,"RSET",NIL);
  138.     smtp_fake (stream,SMTPHARDERROR,"One or more recipients failed");
  139.     return NIL;
  140.   }
  141.                 /* negotiate data command */
  142.   if (!(smtp_send (stream,"DATA",NIL) == SMTPREADY)) return NIL;
  143.                 /* set up error in case failure */
  144.   smtp_fake (stream,SMTPSOFTFATAL,"SMTP connection went away!");
  145.                 /* output data, return success status */
  146.   return rfc822_output (tmp,env,body,smtp_soutr,stream->tcpstream) &&
  147.     (smtp_send (stream,".",NIL) == SMTPOK);
  148. }
  149.  
  150. /* Mail Transfer Protocol turn on debugging telemetry
  151.  * Accepts: stream
  152.  */
  153.  
  154. void smtp_debug (stream)
  155.     SMTPSTREAM *stream;
  156. {
  157.   stream->debug = T;        /* turn on protocol telemetry */
  158. }
  159.  
  160.  
  161. /* Mail Transfer Protocol turn off debugging telemetry
  162.  * Accepts: stream
  163.  */
  164.  
  165. void smtp_nodebug (stream)
  166.     SMTPSTREAM *stream;
  167. {
  168.   stream->debug = NIL;        /* turn off protocol telemetry */
  169. }
  170.  
  171. /* Internal routines */
  172.  
  173.  
  174. /* Simple Mail Transfer Protocol send recipient
  175.  * Accepts: SMTP stream
  176.  *        address list
  177.  *        pointer to error flag
  178.  */
  179.  
  180. void smtp_rcpt (stream,adr,error)
  181.     SMTPSTREAM *stream;
  182.     ADDRESS *adr;
  183.     long *error;
  184. {
  185.   char tmp[MAILTMPLEN];
  186.   while (adr) {
  187.                 /* clear any former error */
  188.     if (adr->error) fs_give ((void **) &adr->error);
  189.     if (adr->host) {        /* ignore group syntax */
  190.       strcpy (tmp,"TO:<");    /* compose "RCPT TO:<return-path>" */
  191.       rfc822_address (tmp,adr);
  192.       strcat (tmp,">");
  193.                 /* send "RCPT TO" command */
  194.       if (!(smtp_send (stream,"RCPT",tmp) == SMTPOK)) {
  195.     *error = T;        /* note that an error occurred */
  196.     adr->error = cpystr (stream->reply);
  197.       }
  198.     }
  199.     adr = adr->next;        /* do any subsequent recipients */
  200.   }
  201. }
  202.  
  203.  
  204. /* Simple Mail Transfer Protocol send command
  205.  * Accepts: SMTP stream
  206.  *        text
  207.  * Returns: reply code
  208.  */
  209.  
  210. long smtp_send (stream,command,args)
  211.     SMTPSTREAM *stream;
  212.     char *command;
  213.     char *args;
  214. {
  215.   char tmp[MAILTMPLEN];
  216.                 /* build the complete command */
  217.   if (args) sprintf (tmp,"%s %s",command,args);
  218.   else strcpy (tmp,command);
  219.   if (stream->debug) mm_dlog (tmp);
  220.   strcat (tmp,"\015\012");
  221.                 /* send the command */
  222.   return tcp_soutr (stream->tcpstream,tmp) ? smtp_reply (stream) :
  223.     smtp_fake (stream,SMTPSOFTFATAL,"SMTP connection went away!");
  224. }
  225.  
  226. /* Simple Mail Transfer Protocol get reply
  227.  * Accepts: SMTP stream
  228.  * Returns: reply code
  229.  */
  230.  
  231. long smtp_reply (stream)
  232.     SMTPSTREAM *stream;
  233. {
  234.                 /* flush old reply */
  235.   if (stream->reply) fs_give ((void **) &stream->reply);
  236.                   /* get reply */
  237.   if (!(stream->reply = tcp_getline (stream->tcpstream)))
  238.     return smtp_fake (stream,SMTPSOFTFATAL,"SMTP connection went away!");
  239.   if (stream->debug) mm_dlog (stream->reply);
  240.                 /* handle continuation by recursion */
  241.   return (stream->reply[3]=='-') ? smtp_reply (stream) : atoi (stream->reply);
  242. }
  243.  
  244.  
  245. /* Simple Mail Transfer Protocol set fake error
  246.  * Accepts: SMTP stream
  247.  *        SMTP error code
  248.  *        error text
  249.  * Returns: error code
  250.  */
  251.  
  252. long smtp_fake (stream,code,text)
  253.     SMTPSTREAM *stream;
  254.     long code;
  255.     char *text;
  256. {
  257.                 /* flush any old reply */
  258.   if (stream->reply ) fs_give ((void **) &stream->reply);
  259.                   /* set up pseudo-reply string */
  260.   stream->reply = (char *) fs_get (20+strlen (text));
  261.   sprintf (stream->reply,"%ld %s",code,text);
  262.   return code;            /* return error code */
  263. }
  264.  
  265. /* Simple Mail Transfer Protocol filter mail
  266.  * Accepts: stream
  267.  *        string
  268.  * Returns: T on success, NIL on failure
  269.  */
  270.  
  271. long smtp_soutr (stream,s)
  272.     void *stream;
  273.     char *s;
  274. {
  275.   char c,*t;
  276.                 /* find lines beginning with a "." */
  277.   while (t = strstr (s,"\015\012.")) {
  278.     c = *(t += 3);        /* remember next character after "." */
  279.     *t = '\0';            /* tie off string */
  280.                 /* output prefix */
  281.     if (!tcp_soutr (stream,s)) return NIL;
  282.     *t = c;            /* restore delimiter */
  283.     s = t - 1;            /* push pointer up to the "." */
  284.   }
  285.                 /* output remainder of text */
  286.   return *s ? tcp_soutr (stream,s) : T;
  287. }
  288.